#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <functional>
#include <sqlite3.h>

#include <random>
#include <sstream>
#include <chrono>
#include <iomanip>
#include <atomic>
#include <fstream>
#include <stdexcept>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cerrno>
#include "Log.hpp"
namespace ns_helper
{
    typedef int (*callback)(void *, int, char **, char **);
    class SqliteHelper
    {
    public:
        SqliteHelper(const std::string &dbfile)
            : _dbfile(dbfile), _handler(nullptr)
        {
        }

        // 打开可读可写的文件,不存在就创建
        bool Open(int safe_leve = SQLITE_OPEN_FULLMUTEX /*默认串行化*/)
        {
            // int sqlite3_open_v2(const char *filename, sqlite3 **ppDb, int flags, const char *zVfs )
            int ret = sqlite3_open_v2(_dbfile.c_str(), &_handler, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | safe_leve, nullptr);
            if (ret != SQLITE_OK)
            {
                std::cout << "sql :" << _dbfile << " ,执行语句" << sqlite3_errmsg(_handler) << std::endl;
                return false;
            }
            return true;
        }

        // 执行语句
        bool Exec(const std::string &sql, callback cb, void *arg)
        {
            // int sqlite3_exec(sqlite3*, char *sql, int (*callback)(void*,int,char**,char**),  void* arg, char **err)
            int ret = sqlite3_exec(_handler, sql.c_str(), cb, arg, nullptr);
            if (ret != SQLITE_OK)
            {
                std::cout << "sql :" << _dbfile << " ,执行语句" << sqlite3_errmsg(_handler) << std::endl;
                return false;
            }
            return true;
        }

        // 关闭
        void Close()
        {
            if (_handler)
                sqlite3_close_v2(_handler);
        }

    private:
        std::string _dbfile;
        sqlite3 *_handler;
    };

    class StrHelper
    {
    public:
        static ssize_t splite(const std::string &str, const std::string &seq, std::vector<std::string> &result)
        {
            // music..pop..#
            ssize_t pos = 0, index = 0;
            while (index < str.size())
            {
                pos = str.find(seq, index);
                if (pos == std::string::npos)
                {
                    // 不存在就截取到末尾
                    result.push_back(str.substr(index));
                    return result.size();
                }

                if (index == pos)
                {
                    // 跳过当前的点
                    index += seq.size();
                    continue;
                }

                result.push_back(str.substr(index, pos - index));
                index = pos + seq.size();
            }
            return result.size();
        }
    };

    class UUIDHelp
    {
    public:
        static std::string get_mac_address()
        {
            std::ifstream file("/sys/class/net/eth0/address"); // 根据实际网络接口名称替换 eth0
            if (!file.is_open())
            {
                throw std::runtime_error("Failed to open MAC address file");
            }

            std::string mac_address;
            std::getline(file, mac_address);

            return mac_address;
        }

        static std::string uuid()
        {
            std::random_device rd;
            std::mt19937_64 generator(rd()); // 梅森旋转算法,以硬件随机为种子
            // 生成8个0~255的数字
            std::uniform_int_distribution<int> distribution(0, 255); // 截取8位

            // 流提取成俩位的十进制
            std::stringstream ss;

            // 生成 8 4 4
            for (int i = 1; i <= 8; i++)
            {
                ss << std::setw(2) << std::setfill('0') << std::hex << distribution(generator);
                if (i == 4 || i == 6 || i == 8)
                    ss << "-";
            }
            // 追加上mac地址后四位
            std::string mac_address = UUIDHelp::get_mac_address().substr(0, 5);
            ss << mac_address << "-";

            static std::atomic<int> atc(1);
            int num = atc.fetch_add(1);
            for (int i = 5; i >= 0; i--)
                ss << std::setw(2) << std::setfill('0') << std::hex << ((num >> i * 6) & 0xff);

            return ss.str();
        }
    };

    class FileHelper
    {
    public:
        FileHelper(const std::string &filename)
            : _filename(filename)
        {
        }
        ~FileHelper()
        {
        }

        bool IsExists()
        {
            struct stat st;
            return !stat(_filename.c_str(), &st);
        }
        ssize_t Size()
        {
            struct stat st;
            if (stat(_filename.c_str(), &st))
            {
                return 0;
            }
            return st.st_size;
        }
        bool Read(char *buffer, ssize_t offset, ssize_t len)
        {
            // 1.打开文件
            std::ifstream ifs(_filename, std::ios::binary | std::ios::in);
            if (!ifs.is_open())
            {
                ELOG("open %s error!", _filename.c_str());
                return false;
            }
            // 2.跳转到指定偏移量
            ifs.seekg(offset, std::ios::beg);
            // 3.读取文件
            ifs.read(buffer, len);
            if (!ifs.good())
            {
                DLOG("read %s error", _filename.c_str());
                ifs.close();
                return false;
            }
            ifs.close();
            return true;
        }

        bool Read(std::string &buffer)
        {
            buffer.resize(Size());
            return Read(&buffer[0], 0, this->Size());
        }

        bool Write(const char *buffer, ssize_t offset, ssize_t len)
        {
            // 设置偏移量必须有可读权限
            // 1.打开文件
            std::fstream fs(_filename, std::ios::binary | std::ios::in | std::ios::out);
            if (false == fs.is_open())
            {
                DLOG("open %s error!", _filename.c_str());
                return false;
            }
            // 2.设置偏移量
            fs.seekp(offset, std::ios::beg);
            // 3.写入数据
            fs.write(buffer, len);
            if (!fs.good())
            {
                DLOG("write %s error", _filename.c_str());
                fs.close();
                return false;
            }
            fs.close();
            return true;
        }

        bool Write(const std::string &buffer)
        {
            return Write(buffer.c_str(), 0, buffer.size());
        }


        bool RenameFile(const std::string &newfilename)
        {
            return !::rename(_filename.c_str(), newfilename.c_str());
        }

        static bool CreateFile(const std::string &filename)
        {
            std::fstream ofs(filename, std::ios::binary | std::ios::out);
            if (!ofs.is_open())
            {
                ELOG("open %s error!", filename.c_str());
                return false;
            }
            ofs.close();
            return true;
        }
        static bool RemoveFile(const std::string &filename)
        {
            if(!FileHelper(filename).IsExists())
                return false;
            return (::remove(filename.c_str()) == 0);
        }

        static std::string ParentDirctory(const std::string &path)
        {
            // a/b/c/d/e
            ssize_t pos = path.find_last_of("/");
            if (pos == std::string::npos)
            {
                // 当前目录 ./abc
                return "./";
            }
            return path.substr(0, pos);
        }

        static bool CreateDirctory(const std::string &path)
        {
            // a/b/c/d ,逐层创建目录
            int pos = 0, index = 0;
            while (index < path.size())
            {
                pos = path.find("/", index);
                if (pos == std::string::npos)
                {
                    return (mkdir(path.c_str(), 0775) == 0);
                }
                std::string parentpath = path.substr(0, pos);
                if (::mkdir(parentpath.c_str(), 0775) && errno != EEXIST)
                {
                    DLOG("mkdir %s fail,error %d, %s", path.c_str(), errno, strerror(errno));
                    return false;
                }
                index = pos + 1;
            }
            return true;
        }

        static bool RemoveDirctory(const std::string &path)
        {
            // a/b/c/d/e
            // rmdir 不能移除不为空的文件
            std::string cmd = "rm -rf" + path;
            return (system(cmd.c_str()) != -1);
        }

    private:
        std::string _filename;
    };
}
